//
//  Quotation.cpp
//  ChartRefactor
//
//  Created by CaoJun on 15/3/2.
//  Copyright (c) 2015年 CaoJun. All rights reserved.
//

#include "Quotation.h"

#include "Quotation.h"
#include "YTXChartTools.h"

#include <queue>
#include <string>
#include <cmath>

#import <Foundation/Foundation.h>

using namespace ytx;
using namespace std;



Quotation::Quotation(string id, string currentDate, LineType::LineType quotationType, string marketType, bool hasVolume, int toFix = 2): id(id),currentDate(currentDate), quotationType(quotationType), marketType(marketType), toFix(toFix), hasVolume(hasVolume), redrawFlag(false)
{

}

Quotation::Quotation(): quotationType(LineType::EMPTY), drawingCount(0),infoTitle(make_pair("", "")),lineRemaind(""), redrawFlag(false)
{

}

Quotation::~Quotation(){
    for (map<string, QuotationHttpBrige*>::iterator iter = requestbehavior.begin(); iter != requestbehavior.end(); iter++) {
        QuotationHttpBrige * brige = (*iter).second;
        [brige invalidate];
    }
}

bool Quotation::equal(const Quotation * other) const{
    return other == NULL ? false : (this == other || (type == other->type && id == other->id && quotationType == other->quotationType));
}

bool Quotation::isRedrawAndClear(){
    bool originFlag = redrawFlag;
    redrawFlag = false;
    return originFlag;
}

bool Quotation::hasData() const
{
    return lineData.size() ? lineData[0].size(): false;
}

bool Quotation::hasData(int index) const
{
    if(hasData()){
        int count = (int)lineData[0].size();
        return 0 <= index && index < count;
    }
    return  false;
}

bool Quotation::hasCrosshairsYData() const
{
    return hasData();
}

void Quotation::calculateIfHasData()
{

}

int Quotation::getDataLength() const{
    return (int)dateData.size();
}

pair<double, double> Quotation::getLineDataMinMax(int startIndex, int endIndex) const
{
    double max = numeric_limits<double>::min(), min = numeric_limits<double>::max();
    if(lineData.size() && lineData[0].size()){
        for (vector<vector<double> >::const_iterator i = lineData.begin(); i != lineData.end(); ++i) {
            const vector<double> & item = *i;
            max = std::max(*(max_element(MIN(item.begin() + startIndex, item.end()-1), MIN(item.begin() + endIndex, item.end()-1), Tools::compareForMax)), max);
            min = std::min(*(min_element(MIN(item.begin() + startIndex, item.end()-1), MIN(item.begin() + endIndex, item.end()-1), Tools::compareForMin)), min);
        }
    }
    else{
        min = numeric_limits<double>::quiet_NaN();
        max = numeric_limits<double>::quiet_NaN();
    }
    return make_pair(min, max);
}

pair<double, double> Quotation::getKLineDataMinMax(int startIndex, int endIndex) const
{
    double max = numeric_limits<double>::min(), min = numeric_limits<double>::max();
    if(kLineData.size()){
        for (vector<KLineItem>::const_iterator i = kLineData.begin() + startIndex; i != kLineData.begin() + endIndex; ++i) {
            const KLineItem & item = *i;
            max = std::max(max, item.high);
            min = std::min(min, item.low);
        }
    }
    else{
        min = numeric_limits<double>::quiet_NaN();
        max = numeric_limits<double>::quiet_NaN();
    }

    return make_pair(min, max);
}

pair<double, double> Quotation::getDataMinMax(int startIndex, int endIndex) const
{
    pair<double, double> lineData = getLineDataMinMax(startIndex, endIndex);
    pair<double, double> kLineData = getKLineDataMinMax(startIndex, endIndex);

    if (std::isnan(lineData.first) || lineData.first < 0) {
        return kLineData;
    }
    else if(std::isnan(kLineData.first)){
        return lineData;
    }

    double min = std::min(lineData.first, kLineData.first),max = std::max(lineData.second, kLineData.second);
    //    dataMax = max;
    //    dataMin = min;
    return make_pair(min, max);
}

DataOption Quotation::createOption(map<string, string> option, string routing){
    return DataOption(option, routing);
}

void Quotation::requestData(const string tag, const DataOption & dataOption, const string acceptableContent)
{
    string url = dataOption.getUrl();
    if (url == "" || url.length() < 8) {// "" || http://
#if DEBUG
        NSLog(@"非法URL");
#endif
        return;
    }
    QuotationHttpBrige * brige =  [[QuotationHttpBrige alloc] initWithQuotation:this withTag:[NSString stringWithUTF8String:tag.c_str()]];
    if (tag.length()) {
        if(requestbehavior.find(tag) != requestbehavior.end()){
            QuotationHttpBrige * brige = (*requestbehavior.find(tag)).second;
            if (brige) return;
        }
        
        requestbehavior.insert(make_pair(tag, brige));
    }
    
    [brige GET:[NSString stringWithUTF8String:url.c_str()] parameters:dataOption.toDictonary() acceptableContent:[NSString stringWithUTF8String:acceptableContent.c_str()] ];
}

void Quotation::firstFailRequestHandler(string tag)
{

}

void Quotation::onFail(string tag)
{
    
}

void Quotation::callback(string tag, string data){
    
}

void Quotation::onFailBehavior(string tag)
{
    if(tag.length() && requestbehavior.find(tag) != requestbehavior.end()){
        requestbehavior.erase(requestbehavior.find(tag));
    }
    onFail(tag);
}

void Quotation::callbackBehavior(string tag, string data)
{
    if(tag.length() && requestbehavior.find(tag) != requestbehavior.end()){
        QuotationHttpBrige * brige = (*requestbehavior.find(tag)).second;
        [brige invalidate];
        requestbehavior.erase(requestbehavior.find(tag));
    }
    callback(tag, data);
}



std::pair<double, double> Quotation::getAdjustedDataMinMax(int startIndex, int endIndex,const Rectangle & rect) const
{
    return getDataMinMax(startIndex, endIndex);
}

string Quotation::getCrosshairXData(int index){
    //已经是正确的index
    return dateData[index];
}

double Quotation::getCrosshairXValue(int index){
    return 0;
}


UpDropStatus::UpDropStatus Quotation::getUpDropStatus(int index){
    return UpDropStatus::Drop;
}

pair<std::string, std::string> Quotation::getTopSideInfoText() const
{
    return infoTitle;
}

//视图内最后个
vector<pair<string, string> > Quotation::getTopSideText() const
{
    return getTopSideText(getDataLength() - 1);
}

int Quotation::fixIndexRange(int index) const{
    return Tools::between(0, getDataLength()-1, index);
}

//试图内index个
vector<pair<string, string> > Quotation::getTopSideText(int index) const
{
    return getTopSideText(lineData, fixIndexRange(index));
}

vector<pair<string, string> > Quotation::getTopSideText(const vector<vector<double> > & data, int index) const
{
    //值 颜色
    vector<pair<string, string> > result;

    if(hasData(index) && titleType.size() <= data.size() * 2){
        int i = 0;
        for (vector<string>::const_iterator it = titleType.begin(); it < titleType.end(); it += 2) {
            i = (int)(it - titleType.begin());
            string text = std::isnan(data[i / 2][index]) ? "--":Tools::Convert2FixString(data[i / 2][index], toFix);
            result.push_back(make_pair(titleType[i + 1] + ":" + text , titleType[i]));
        }
    } else if (hasData(index) && data.size() * 2 < titleType.size()) {
        //想要显示的数据小于预设置数据的情况
        int i = 0;
        for(i = 0 ; i< data.size() ; i++)
        {
            string text = std::isnan(data[i][index]) ? "--":Tools::Convert2FixString(data[i][index], toFix);
            result.push_back(make_pair(titleType[i + 1] + ":" + text , titleType[i]));
        }
    }

    return result;
}

LineType::LineType Quotation::getQuotationType() {
    return quotationType;
}

void Quotation::setQuotationType(LineType::LineType quotationType) {
    this->quotationType = quotationType;
}

std::string Quotation::getMarketType() {
    return marketType;
}

void Quotation::setMarketType(std::string marketType) {
    this->marketType = marketType;
}

int Quotation::getToFix() {
    return toFix;
}

void Quotation::setToFix(int toFix) {
    this->toFix = toFix;
}

QuotationType::QuotationType Quotation::getType() {
    return type;
}

void Quotation::setType(QuotationType::QuotationType type) {
    this->type = type;
}

YTXTime Quotation::getDateTo() {
    return dateTo;
}

void Quotation::setDateTo(YTXTime dateTo) {
    this->dateTo = dateTo;
}

YTXTime Quotation::getDateFrom() {
    return dateFrom;
}

void Quotation::setDateFrom(YTXTime dateFrom) {
    this->dateFrom = dateFrom;
}

int Quotation::getDrawingCount() {
    return drawingCount;
}

void Quotation::setDrawingCount(int drawingCount) {
    this->drawingCount = drawingCount;
}

std::string Quotation::getQuotationName() {
    return QuotationName;
}

void Quotation::setQuotationName(std::string quotationName) {
    QuotationName = quotationName;
}

std::string Quotation::getId() {
    return id;
}

void Quotation::setId(std::string id) {
    this->id = id;
}

YTXTime Quotation::getDay() {
    return day;
}

void Quotation::setDay(YTXTime day) {
    this->day = day;
}

double Quotation::getPrevValue() {
    return prevValue;
}

void Quotation::setPrevValue(double prevValue) {
    this->prevValue = prevValue;
}

std::vector<std::string> & Quotation::getTitleType() {
    return titleType;
}

void Quotation::setTitleType(std::vector<std::string> & titleType) {
    this->titleType = titleType;
}

std::string Quotation::getNickName() {
    return nickName;
}

void Quotation::setNickName(std::string nickName) {
    this->nickName = nickName;
}

const std::vector<string> & Quotation::getDateData() {
    return dateData;
}

void Quotation::setDateData(std::vector<string> & dateData) {
    this->dateData = dateData;
}

std::vector<std::vector<double> > & Quotation::getLineData() {
    return lineData;
}

void Quotation::setLineData(std::vector<std::vector<double> > & lineData) {
    this->lineData = lineData;
}

std::vector<KLineItem> & Quotation::getKLineData() {
    return kLineData;
}

void Quotation::setKLineData(std::vector<KLineItem> & klineData) {
    this->kLineData = klineData;
}

std::vector<std::vector<double> > & Quotation::getLineTypeData() {
    return lineTypeData;
}

void Quotation::setLineTypeData(std::vector<std::vector<double> > & lineTypeData) {
    this->lineTypeData = lineTypeData;
}

std::vector<std::string> & Quotation::getTimeString() {
    return timeString;
}

void Quotation::setTimeString(std::vector<std::string> & timeString) {
    this->timeString = timeString;
}

ytx::Rect & Quotation::getRow() {
    return row;
}

void Quotation::setRow(const ytx::Rect & row) {
    this->row = row;
}

ytx::Rect & Quotation::getColumn() {
    return column;
}

void Quotation::setColumn(const ytx::Rect & column) {
    this->column = column;
}

const TimeString & Quotation::getOriginTimeString() const {
    return originTimeString;
}

void Quotation::setOriginTimeString (const TimeString & originTimeString) {
    this->originTimeString = originTimeString;
}

ytx::Rect & Quotation::getOriginRow() {
    return originRow;
}

void Quotation::setOriginRow(ytx::Rect & originRow) {
    this->originRow = originRow;
}

ytx::Rect & Quotation::getOriginColumn() {
    return originColumn;
}

void Quotation::setOriginColumn(ytx::Rect & originColumn) {
    this->originColumn = originColumn;
}

std::string Quotation::getLineRemaind() {
    return lineRemaind;
}

void Quotation::setLineRemaind(std::string lineRemaind) {
    this->lineRemaind = lineRemaind;
}

const vector<string> & Quotation::getBottomSideText(SizeType::SizeType widthType) const
{
    return timeString;
}

void Quotation::queue(std::string taskName)
{
    task.push_back(taskName);

    if(task.front() != "inprogress") {
        dequeue();
    }
}
void Quotation::dequeue()
{
    if(!task.size()){
        return;
    }
    string last = task.front();
    task.erase(task.begin());

    if (last == "inprogress") {
        if(!task.size()){
            return;
        }
        last = task.front();
        task.erase(task.begin());
    }

    task.insert(task.begin(), "inprogress");
    taskFactory(last);
}
void Quotation::taskFactory(std::string taskName)
{

}

void Quotation::registerBehavior(std::string eventName, std::string behaviorName)
{
    //    if(behavior.find(eventName) == behavior.end()){
    //        std::queue<string> tempQueue;
    //        behavior.insert(make_pair(eventName, tempQueue));
    //    }

    //    behavior[eventName]

    behavior[eventName].push(behaviorName);

    //    behaviorList.push(behaviorName);

}

void Quotation::executeBehavior(std::string eventName)
{
    if(behavior.find(eventName) == behavior.end()){
        std::queue<string> tempQueue;
        behavior.insert(make_pair(eventName, tempQueue));
    }

    std::queue<string> & behaviorList = (*behavior.find(eventName)).second;

    while (!behaviorList.empty()) {
        behaviorFactory(behaviorList.front());
        behaviorList.pop();
    }
}

void Quotation::behaviorFactory(std::string behaviorName)
{

}

void Quotation::cleanData(){
    lineData.clear();
    kLineData.clear();
    dateData.clear();
    task.clear();
    lineDataDrawPartIndex.clear();
}


bool Quotation::isHasVolume() {
    return hasVolume;
}

void Quotation::setHasVolume(bool hasVolume) {
    this->hasVolume = hasVolume;
}

#pragma mark -
@interface QuotationHttpBrige ()

@property(nonatomic, nullable, strong) AFHTTPSessionManager *manager;

@end

@implementation QuotationHttpBrige

- (void)GET:(NSString *)URLString
 parameters:(id)parameters acceptableContent:(NSString *)acceptableContent
{
    self.manager.requestSerializer = [AFJSONRequestSerializer serializer];
    NSLog(@"GET:%@\nurl:%@\n%@",self.tag,URLString,parameters);
    [self.manager POST:URLString parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
        NSLog(@"Success//GET:%@",self.tag);
        // ret = -1 是 参数错误
        // ret = -2 是 没有数据
        std::string tag = std::string([self.tag UTF8String]);
        NSString * str = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];

        std::string data = std::string([str UTF8String]);
        self.quotation->callbackBehavior(tag, data);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"Error//GET:%@",self.tag);
        std::string tag = std::string([self.tag UTF8String]);

        if (![error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"已取消"]) {
            self.quotation->onFailBehavior(tag);
            self.quotation->firstFailRequestHandler(tag);
        }
    }];
}

- (void)GET:(NSString *)URLString
                     parameters:(id)parameters;
{
    [self GET:URLString parameters:parameters acceptableContent: @"text/plain"];
}

- (instancetype)initWithQuotation:(ytx::Quotation *)quotation
                          withTag:(NSString *)tag
{
    self = [super init];
    self.quotation = quotation;
    self.tag = tag;
    
    return self;
}

- (AFHTTPSessionManager *)manager
{
    if (!_manager) {
        _manager = [AFHTTPSessionManager manager];
        _manager.responseSerializer = [AFHTTPResponseSerializer serializer];
        
    }
    return _manager;
}

- (void)invalidate
{
    for (NSURLSessionTask *task in self.manager.tasks) {
        [task cancel];
    };
}

@end

